<template>
    <el-container>
        <el-aside width="260px" v-loading="menuloading">
            <el-container>
                <el-header>
                    <el-input v-model="menuFilter" clearable placeholder="输入关键字进行过滤" />
                    <el-button icon="el-icon-search" type="primary" @click="search" />
                </el-header>
                <el-main style="background-color: #FFFFFF;">
                    <el-tabs>
                        <el-tab-pane label="表结构">
                            <el-scrollbar>
                                <div class="tree-container">
                                    <div v-for="(table, index) in treeData" :key="table.table" class="tree-table">
                                        <div class="tree-table-name" @click="onFoldTable(index)">
                                            <span class="tree-fold-btn"
                                                :class="['tree-fold-btn', foldIndex.includes(index) ? 'el-icon-remove-outline' : 'el-icon-circle-plus-outline']" />
                                            <img src="@/assets/table.png" width="15px">
                                            {{ table.table }}
                                        </div>
                                        <template v-if="table.fields.length > 0 && foldIndex.includes(index)">
                                            <div v-for="field in table.fields" :key="field.name" class="tree-table-field">
                                                {{ field.COLUMN_NAME }}
                                                <!-- <span class="el-icon-document-copy"></span> -->
                                            </div>
                                        </template>
                                    </div>
                                </div>
                            </el-scrollbar>
                        </el-tab-pane>
                        <el-tab-pane label="命令集">
                            <el-scrollbar>
                                <ul class="order-list">
                                    <li v-for="item in commitsList" :key="item.createTime" @click="copySQLOrder(item)">
                                        <img src="@/assets/order.png">
                                        {{ item.title }}
                                    </li>
                                </ul>
                            </el-scrollbar>
                        </el-tab-pane>
                    </el-tabs>
                </el-main>
            </el-container>
        </el-aside>
        <el-main class="nopadding">
            <el-container>
                <el-header>
                    <div class="left-panel">
                        <el-button-group>
                            <el-button type="primary" plain icon="el-icon-plus" @click="runCode()">运行</el-button>
                            <el-button type="primary" plain icon="el-icon-delete" @click="stopRun()">停止</el-button>
                            <el-button type="danger" plain icon="el-icon-delete" @click="commit()">提交</el-button>
                        </el-button-group>
                        <el-divider direction="vertical"></el-divider>
                        <el-button type="success" plain icon="el-icon-delete" @click="format()">美化</el-button>
                    </div>
                    <div class="right-panel">
                        <div class="right-panel-search">
                        </div>
                    </div>
                </el-header>
                <el-main class="nopadding">
                    <textarea ref="codeMirror"></textarea>
                    <div class="tables-result" :style="{ height: `${tablesHeight}px` }">
                        <el-tabs type="border-card" style="height: 99%">
                            <el-tab-pane label="信息">
                                <span v-if="runType === 0" class="el-icon-info" style="color: #909399;"></span>
                                <span v-if="runType === 1" class="el-icon-success" style="color: #67C23A;"></span>
                                <span v-if="runType === 2" class="el-icon-warning" style="color: #E6A23C;"></span>
                                <span v-if="runType === 3" class="el-icon-error" style="color: #F56C6C;"></span>
                                {{ runResult }}
                                <template v-if="runType === 3">
                                    <div class="error-message"><b>message：</b>{{ errMsg.sqlMessage }}</div>
                                    <div class="error-message"><b>errno：</b>{{ errMsg.errno }}</div>
                                    <div class="error-message"><b>sql：</b>"{{ errMsg.sql }}"</div>
                                    <div class="error-message"><b>code：</b>{{ errMsg.code }}</div>
                                    <div class="error-message"><b>sqlState：</b>{{ errMsg.sqlState }}</div>
                                </template>
                            </el-tab-pane>
                            <el-tab-pane label="结果">
                                <el-scrollbar>
                                    <el-table :data="tableData" border>
                                        <el-table-column v-for="item in columns" :key="item.value" :prop="item.value"
                                            :label="item.label" :show-overflow-tooltip="true" :minWidth="item.minWidth"
                                            :width="item.width" />
                                    </el-table>
                                </el-scrollbar>
                            </el-tab-pane>
                        </el-tabs>
                    </div>
                </el-main>
            </el-container>
        </el-main>
    </el-container>
</template>
  
<script>
// 核心样式
import 'codemirror/lib/codemirror.css'

// 引入主题后还需要在 options 中指定主题才会生效
import 'codemirror/addon/display/fullscreen.css' // 全屏显示编辑器
import 'codemirror/addon/display/fullscreen.js' // 全屏显示编辑器

import 'codemirror/theme/cobalt.css'
import 'codemirror/theme/eclipse.css'
import 'codemirror/theme/ayu-dark.css'
import 'codemirror/theme/idea.css'
import 'codemirror/theme/solarized.css'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/sql-hint.js'
import 'codemirror/addon/selection/active-line.js'
import 'codemirror/addon/edit/matchbrackets.js'
import 'codemirror/mode/sql/sql'
import CodeMirror from 'codemirror'
import { format } from 'sql-formatter'

export default {
    name: 'Home',
    data() {
        return {
            menuloading: false,//列表加载标记
            menuFilter: '',//列表过滤条件
            winHeight: 0,
            tablesHeight: 0,
            foldIndex: [], // 记录展开状态的表结构，存入index
            treeData: [], // 左侧展示的表结构
            tableList: [],// 所有表格信息
            runResult: '暂无数据', // 运行结果提示
            runType: 0, // 运行结果类型，0无结果、1成功、2警告、3异常
            tableData: [], // 运行结果的表数据展示
            columns: [], // 运行的表结构，对象元素，{label: '', value: ''}
            sqlEditor: null,
            options: {
                theme: '',
                // lineNumbers: true,
                styleActiveLine: true,
                lineWrapping: true,
            },
            code: '', // 实时输入的代码
            runLoading: false, // 运行加载状态
            commitsList: [],
            errMsg: {
                sqlMessage: '',
                errno: '',
                sql: '',
                code: '',
                sqlState: ''
            }
        }
    },
    created() {
        this.queryTables()
    },
    mounted() {
        this.init();
    },
    methods: {
        init() {
            this.sqlEditor = CodeMirror.fromTextArea(this.$refs.codeMirror, {
                mode: "text/x-sparksql", // spark sql模式
                lineNumbers: this.options.lineNumbers,  // 显示行号
                styleActiveLine: this.options.styleActiveLine, // 激活当前行
                theme: this.options.theme, // 主题
                lineWrapping: this.options.lineWrapping, // 自动换行
                matchBrackets: true, // 括号匹配
                autoCloseBrackets: true,
                line: true,
                extraKeys: { // 触发提示按键
                    [this.options.extraKeys]: "autocomplete"
                },
                hintOptions: { // 自定义提示选项
                    completeSingle: false, // 当匹配只有一项的时候是否自动补全
                    tables: {} // 代码提示
                },
            })
            this.setValue()
            this.editorEvents()
        },
        onFoldTable(index) {
            // 表结构折叠事件
            const i = this.foldIndex.indexOf(index)
            if (i === -1) {
                this.foldIndex.push(index)
            } else {
                this.foldIndex.splice(i, 1)
            }
        },
        search() {
            if (!this.tableList) {
                return;
            }
            this.treeData = []
            const tips = {}
            this.tableList.forEach(async (table) => {
                if (table.name && table.name.indexOf(this.menuFilter) >= 0) {
                    const treeObj = {
                        table: table.name,
                        fields: []
                    }
                    tips[table.name] = []

                    // 查询表中的字段
                    // const fieldRes = await this.$API.devsql.column.get({ 'table': table.name });
                    // if (fieldRes != null && fieldRes.code == 200) {
                    //     treeObj.fields = [...fieldRes.data]
                    //     fieldRes.data.forEach(f => {
                    //         tips[table.name].push(f.COLUMN_NAME)
                    //     });
                    // }

                    this.treeData.push(treeObj)
                }
            })
            this.setHintOptions(tips)
        },
        format() {
            // 格式化代码
            if (this.sqlEditor.getValue().trim() === '') {
                this.$message.warning('请先编辑 SQL 命令！')
                return
            }
            const sqlCode = this.sqlEditor.getValue()
            this.sqlEditor.setValue(format(sqlCode))
        },
        runCode() {
            this.executeSql();
        },
        stopRun() {

        },
        commit() {
            // SQL编辑器提交事件
            var code = this.$TOOL.trim(this.code || '');
            if (code === '') {
                this.$message.warning('请先编辑 SQL 命令！')
                return
            }
            this.$prompt('请输入命令标题：', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                inputValidator: (val) => {
                    if (val.trim() === '') {
                        return false
                    }
                    return true
                },
                inputErrorMessage: '命令标题不能为空'
            }).then(({ value }) => {
                if (value.trim() !== '') {
                    const logs = {
                        title: value,
                        sql: code,
                        createTime: Date.now()
                    }
                    this.addLogs(logs)
                    this.$message.success('提交成功！')
                } else {
                    this.$message.error('提交失败！')
                }
            }).catch(() => {
                this.$message.warning('已取消提交')
            })
        },
        setValue(sql) {
            this.sqlEditor.setValue(sql || '')
        },
        setHintOptions(tables) {
            this.sqlEditor.options.hintOptions.tables = tables
        },
        editorEvents() {
            // 设置代码提示
            this.sqlEditor.on('keyup', (cm, event) => {
                if (event.keyCode >= 65 && event.keyCode <= 90) {
                    cm.showHint();
                }
                //所有的字母和'$','{','.'在键按下之后都将触发自动完成  
                if (!cm.state.completionActive &&
                    ((event.keyCode >= 65 && event.keyCode <= 90) || event.keyCode == 52 || event.keyCode == 219 || event.keyCode == 190)) {
                    CodeMirror.commands.autocomplete(cm, null, { completeSingle: false });
                }
            })

            // 代码输入的双向绑定
            this.sqlEditor.on('change', (editor) => {
                // 这里要用多一个载体去获取值,不然会重复赋值卡顿
                this.code = editor.getValue()
                if (this.$emit) {
                    this.$emit('input', this.code)
                }
            })
        },
        copySQLOrder(item) {
            // 复制命令
            this.sqlEditor.setValue(item.sql)
        },
        async executeSql() {
            // 执行SQL语句
            var code = this.$TOOL.trim(this.code || '');
            if (code === '') {
                this.$message.warning('请先编辑 SQL 命令！')
                return
            }
            this.runLoading = true
            this.tableData = []
            this.columns = []
            this.runResult = '执行中...'
            this.runType = 0
            this.errMsg = {}
            const res = await this.$API.devsql.execute.post({ sql: code });
            if (res == null || res.code != 200) {
                return;
            }

            var data = res.data;
            if (data.success) {
                if (data.type == 1) {
                    this.runType = 1
                    this.runResult = `成功查询 ${data.totalItems} 条数据`
                    if (data.data.length > 0) {
                        this.tableData = [...data.data];
                        const obj = { ...this.tableData[0] }
                        for (let key in obj) {
                            this.columns.push({
                                label: key,
                                value: key,
                                width: this.get_width(key),
                                minWidth: this.get_width(key)
                            })
                        }
                    }
                }
                else {
                    this.runType = 1
                    this.runResult = `执行成功！${data.qty}行数据受影响`
                    this.queryTables()
                }
            } else {
                this.runType = 3
                this.runResult = '执行失败！'
                this.errMsg = data.message
            }
            this.runLoading = false
        },
        get_width(key) {
            return key.length * 8 + 60;
        },
        async queryTables() {
            this.menuloading = true;
            // 查询所有表
            const res = await this.$API.devsql.list.get();
            if (res.code != 200) {
                this.menuloading = false;
                return;
            }

            this.tableList = res.data;
            const data = res.data;
            if (data != null && data.length > 0) {
                this.treeData = []
                const tips = {}
                data.forEach(async (table) => {
                    if (table.name && table.name.trim() !== '') {
                        const treeObj = {
                            table: table.name,
                            fields: []
                        }
                        tips[table.name] = []

                        // 查询表中的字段
                        // const fieldRes = await this.$API.devsql.column.get({ 'table': table.name });
                        // if (fieldRes != null && fieldRes.code == 200) {
                        //     treeObj.fields = [...fieldRes.data]
                        //     fieldRes.data.forEach(f => {
                        //         tips[table.name].push(f.COLUMN_NAME)
                        //     });
                        // }

                        this.treeData.push(treeObj)
                    }
                })
                this.setHintOptions(tips)
            }
            this.menuloading = false;
        }
    }
}
</script>

<style lang="scss" scoped></style>
  